# ----------------------------------------------------------------------------
# pytform
# Copyright (c) 2008, Michael Henrique Siegwarth
# All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions 
# are met:
#
#  * Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#  * Redistributions in binary form must reproduce the above copyright 
#    notice, this list of conditions and the following disclaimer in
#    the documentation and/or other materials provided with the
#    distribution.
#  * Neither the name of pytform nor the names of its
#    contributors may be used to endorse or promote products
#    derived from this software without specific prior written
#    permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ----------------------------------------------------------------------------

from math import radians, degrees
import Box2D2 as box2d

class GameObject(object):
    def __init__(self, x, y, angle, fixed_rotation, world):
        body_def = box2d.b2BodyDef()
        body_def.position.Set(x, y)
        body_def.angularDamping = 0.01
        body_def.angle = radians(angle)

        if fixed_rotation == True:
            body_def.fixedRotation = True
        
        # Sometimes there is no world to add the object to
        if world != None:
            self.body = world.CreateBody(body_def)
        else:
            self.body = None
        
        # Object id to use in events
        self.id = 0
        
        # Default events for this object
        # Each object should implement its events
        self.events = []

        # Holds pyglet's vertex information, like
        # position vertices, texture vertices and color
        # This is an array of vertex lists. Each item corresponds
        # to a shape of this object
        self.vertex_list = []

        # Group the vertex list belongs to
        self.group = None
        
    def get_position(self):
        return self.body.GetPosition().tuple()

    def set_position(self, (x, y)):
        self.body.SetXForm(box2d.b2Vec2(x, y), self.body.GetAngle())
        
    position = property(get_position, set_position)

    def contains(self, coords):
        c = box2d.b2Vec2()
        c.fromTuple(coords)

        shape = self.body.GetShapeList()
        while shape:
            if shape.TestPoint(self.body.GetXForm(), c):
                return True

            shape = shape.GetNext()  

        return False

    def move(self, (x, y)):
        pos = self.body.GetPosition()
        self.body.SetXForm(box2d.b2Vec2(pos.x + x, pos.y + y), self.body.GetAngle())

        self.update_vertices()

    def rotate(self, angle):
        self.body.SetXForm(self.body.GetPosition(), self.body.GetAngle() + radians(angle))

        self.update_vertices()

    def update_vertices(self):
        counter = len(self.vertex_list) - 1
        shape = self.body.GetShapeList()

        while shape:          
            shape_v = shape.getAsType().getVertices_b2Vec2()

            temp_v = []
            for v in shape_v:
                t = self.body.GetWorldPoint(v).tuple()
                temp_v.append(t[0])
                temp_v.append(t[1])

            self.vertex_list[counter].vertices = temp_v

            counter -= 1
            shape = shape.GetNext()
    
    def get_v(self):
        # TODO - Use better values here
        smallest_x = 1000000
        smallest_y = 1000000
        largest_x = -1000000
        largest_y = -1000000

        shape = self.body.GetShapeList()

        while shape:          
            shape_v = shape.getAsType().getVertices_b2Vec2()
            
            for v in shape_v:
                t = self.body.GetWorldPoint(v).tuple()
                if t[0] < smallest_x:
                    smallest_x = t[0]
                if t[0] > largest_x:
                    largest_x = t[0]
                if t[1] < smallest_y:
                    smallest_y = t[1]
                if t[1] > largest_y:
                    largest_y = t[1]

            shape = shape.GetNext()
                
        return [(smallest_x, smallest_y),
                (smallest_x, largest_y),
                (largest_x, largest_y),
                (largest_x, smallest_y)]
    
    def set_v(self):
        pass

    vertices = property(get_v, set_v)

    def get_angle(self):
        return degrees(self.body.GetAngle())

    def set_angle(self, angle):
        self.body.SetXForm(self.body.GetPosition(), radians(angle))

    angle = property(get_angle, set_angle)

    def delete_vertex_lists(self):
        for v in self.vertex_list:
            v.delete()
